home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / libc / vfprintf.c < prev    next >
C/C++ Source or Header  |  1990-10-16  |  22KB  |  960 lines

  1. /* 
  2.  * vfprintf.c --
  3.  *
  4.  *    Source code for the "vfprintf" library procedure.
  5.  *
  6.  * Copyright 1988 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /sprite/src/lib/c/stdio/RCS/vfprintf.c,v 1.19 90/10/16 16:41:36 shirriff Exp $ SPRITE (Berkeley)";
  18. #endif not lint
  19.  
  20. #include <ctype.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <varargs.h>
  25. #include <math.h>
  26.  
  27. #ifndef TRUE
  28. #define TRUE 1
  29. #endif
  30. #ifndef FALSE
  31. #define FALSE 0
  32. #endif
  33.  
  34. /*
  35.  * The following defines the size of buffer needed to hold the ASCII
  36.  * digits for the largest floating-point number and the largest integer.
  37.  */
  38.  
  39. #define CVT_DBL_BUF_SIZE 320
  40. #define CVT_INT_BUF_SIZE 33
  41.  
  42. /*
  43.  *----------------------------------------------------------------------
  44.  *
  45.  * CvtUtoA --
  46.  *
  47.  *    Convert a number from internal form to a sequence of
  48.  *    ASCII digits.
  49.  *
  50.  * Results:
  51.  *    The return value is a pointer to the ASCII digits representing
  52.  *    i, and *lengthPtr will be filled in with the number of digits
  53.  *    stored at the location pointed to by the return value.  The
  54.  *    return value points somewhere inside buf, but not necessarily
  55.  *    to the beginning.  Note:  the digits are left null-terminated.
  56.  *
  57.  * Side effects:
  58.  *    None.
  59.  *
  60.  *----------------------------------------------------------------------
  61.  */
  62.  
  63. static char *
  64. CvtUtoA(i, base, buf, lengthPtr, capsFlag)
  65.     register unsigned i;    /* Value to convert. */
  66.     register int base;        /* Base for conversion.  Shouldn't be
  67.                  * larger than 36.  2, 8, and 16
  68.                  * execute fastest.
  69.                  */
  70.     register char *buf;        /* Buffer to use to hold converted string.
  71.                  * Must hold at least CVT_INT_BUF_SIZE bytes. */
  72.     int *lengthPtr;        /* Number of digits is stored here. */
  73.     int capsFlag;        /* 1 if want capital abcd... */
  74. {
  75.     register char *p;
  76.     register char hexOffset = (capsFlag ? 'A': 'a')-'9'-1;
  77.  
  78.     /*
  79.      * Handle a zero value specially.
  80.      */
  81.  
  82.     if (i == 0) {
  83.     buf[0] = '0';
  84.     buf[1] = 0;
  85.     *lengthPtr = 1;
  86.     return buf;
  87.     }
  88.  
  89.     /*
  90.      * Build the string backwards from the end of the result array.
  91.      */
  92.  
  93.     p = &buf[CVT_INT_BUF_SIZE-1];
  94.     *p = 0;
  95.  
  96.     switch (base) {
  97.  
  98.     case 2:
  99.         while (i != 0) {
  100.         p -= 1;
  101.         *p = '0' + (i & 01);
  102.         i >>= 1;
  103.         }
  104.         break;
  105.     
  106.     case 8:
  107.         while (i != 0) {
  108.         p -= 1;
  109.         *p = '0' + (i & 07);
  110.         i >>= 3;
  111.         }
  112.         break;
  113.     
  114.     case 16:
  115.         while (i !=0) {
  116.         p -= 1;
  117.         *p = '0' + (i & 0xf);
  118.         if (*p > '9') {
  119.             *p += hexOffset;
  120.         }
  121.         i >>= 4;
  122.         }
  123.         break;
  124.     
  125.     default:
  126.         while (i != 0) {
  127.         p -= 1;
  128.         *p = '0' + (i % base);
  129.         if (*p > '9') {
  130.             *p += hexOffset;
  131.         }
  132.         i /= base;
  133.         }
  134.         break;
  135.     }
  136.  
  137.     *lengthPtr = (&buf[CVT_INT_BUF_SIZE-1] - p);
  138.     return p;
  139. }
  140.  
  141. /*
  142.  *----------------------------------------------------------------------
  143.  *
  144.  * CvtFtoA --
  145.  *
  146.  *    This procedure converts a double-precision floating-point
  147.  *    number to a string of ASCII digits.
  148.  *
  149.  * Results:
  150.  *    The characters at buf are modified to hold up to numDigits ASCII
  151.  *    characters, followed by a null character.  The digits represent
  152.  *    the most significant numDigits digits of value, with the lowest
  153.  *    digit rounded.  The value at *pointPtr is modified to hold
  154.  *    the number of characters in buf that precede the decimal point.
  155.  *    A negative value of *pointPtr means zeroes must be inserted
  156.  *    between the point and buf[0].  If value is negative, *signPtr
  157.  *    is set to TRUE;    otherwise it is set to FALSE.  The return value
  158.  *    is the number of digits stored in buf, which is either:
  159.  *    (a) numDigits (if the number is so huge that all numDigits places are
  160.  *        used before getting to the right precision level, or if
  161.  *        afterPoint is -1)
  162.  *    (b) afterPoint + *pointPtr (the normal case if afterPoint isn't -1)
  163.  *    If there were no significant digits within the specified precision,
  164.  *    then *pointPtr gets set to -afterPoint and 0 is returned.
  165.  *
  166.  * Side effects:
  167.  *    None.
  168.  *
  169.  *----------------------------------------------------------------------
  170.  */
  171.  
  172. static int
  173. CvtFtoA(value, numDigits, afterPoint, pointPtr, signPtr, buf, fpError)
  174.     double value;        /* Value to be converted. */
  175.     int numDigits;        /* Maximum number of significant digits
  176.                  * to generate in result. */
  177.     int afterPoint;        /* Maximum number of digits to generate
  178.                  * after the decimal point.  If -1, then
  179.                  * there there is no limit. */
  180.     int *pointPtr;        /* Will be filled in with position of
  181.                  * decimal point (number of digits before
  182.                  * decimal point). */
  183.     int *signPtr;        /* Modified to indicate whether or not
  184.                  * value was negative. */
  185.     char *buf;            /* Place to store ASCII digits.  Must hold
  186.                  * at least numDigits+1 bytes. */
  187.     int *fpError;               /* pointer to flag that is set if the number
  188.                                    is not a valid number. */
  189.  
  190. {
  191.     register char *p;
  192.     double fraction, intPart;
  193.     int i, numDigits2;
  194.     char tmpBuf[CVT_DBL_BUF_SIZE];
  195.                 /* Large enough to hold largest possible
  196.                  * floating-point number.
  197.                  */
  198.  
  199.     /*
  200.      * Take care of the sign.
  201.      */
  202.  
  203.     if (signbit(value)) {
  204.     *signPtr = TRUE;
  205.     value = -value;
  206.     } else {
  207.     *signPtr = FALSE;
  208.     }
  209.  
  210.     /*
  211.      * Make sure the value is a valid number
  212.      */
  213.     if (isinf(value)) {
  214.     /*
  215.      * Set the error flag so the invoking function will know
  216.      * that something is wrong.
  217.      */
  218.     *fpError = TRUE;
  219.     strcpy(buf, "Inf");
  220.     return sizeof("Inf") - 1;
  221.     }
  222.     if (isnan(value)) {
  223.     *fpError = TRUE;
  224.     strcpy(buf, "NaN");
  225.     return sizeof("NaN") - 1;
  226.     }
  227.  
  228.     *fpError = FALSE;
  229.  
  230.     /*
  231.      * Divide value into an integer and a fractional component.  Convert
  232.      * the integer to ASCII in a temporary buffer, then move the characters
  233.      * to the real buffer (since we're converting from the bottom up,
  234.      * we won't know the highest-order digit until last).
  235.      */
  236.  
  237.     fraction = modf(value, &intPart);
  238.     *pointPtr = 0;
  239.     for (p = &tmpBuf[CVT_DBL_BUF_SIZE-1]; intPart != 0; p -= 1) {
  240.     double tmp;
  241.     char digit;
  242.  
  243.     tmp = modf(intPart/10.0, &intPart);
  244.  
  245.     digit = (tmp * 10.0) + .2;
  246.     *p = digit + '0';
  247.     *pointPtr += 1;
  248.     }
  249.     p++;
  250.     for (i = 0; (i <= numDigits) && (p <= &tmpBuf[CVT_DBL_BUF_SIZE-1]);
  251.         i++, p++) {
  252.     buf[i] = *p;
  253.     }
  254.  
  255.     /*
  256.      * If the value was zero, put an initial zero in the buffer
  257.      * before the decimal point.
  258.      */
  259.     
  260.     if (value == 0.0) {
  261.     buf[0] = '0';
  262.     i = 1;
  263.     *pointPtr = 1;
  264.     }
  265.  
  266.     /*
  267.      * Now handle the fractional part that's left.  Repeatedly multiply
  268.      * by 10 to get the next digit.  At the beginning, the value may be
  269.      * very small, so do repeated multiplications until we get to a
  270.      * significant digit.
  271.      */
  272.     
  273.     if ((i == 0) && (fraction > 0)) {
  274.     while (fraction < .1) {
  275.         fraction *= 10.0;
  276.         *pointPtr -= 1;
  277.     };
  278.     }
  279.  
  280.     /*
  281.      * Compute how many total digits we should generate, taking into
  282.      * account both numDigits and afterPoint.  Then generate the digits.
  283.      */
  284.     
  285.     numDigits2 = afterPoint + *pointPtr;
  286.     if ((afterPoint < 0) || (numDigits2 > numDigits)) {
  287.     numDigits2 = numDigits;
  288.     }
  289.     
  290.     for ( ; i <= numDigits2; i++) {
  291.     double tmp;
  292.     char digit;
  293.  
  294.     fraction = modf(fraction*10.0, &tmp);
  295.  
  296.     digit = tmp;
  297.     buf[i] = digit + '0';
  298.     }
  299.  
  300.     /*
  301.      * The code above actually computed one more digit than is really
  302.      * needed.  Use it to round the low-order significant digit, if
  303.      * necessary.  This could cause rounding to propagate all the way
  304.      * back through the number.
  305.      */
  306.     
  307.     if ((numDigits2 >= 0) && (buf[numDigits2] >= '5')) {
  308.     for (i = numDigits2-1; ; i--) {
  309.         if (i < 0) {
  310.         int j;
  311.  
  312.         /*
  313.          * Must slide the entire buffer down one slot to make
  314.          * room for a leading 1 in the buffer.  Careful: if we've
  315.          * already got numDigits digits, must drop the last one to
  316.          * add the 1.
  317.          */
  318.  
  319.         for (j = numDigits2; j > 0; j--) {
  320.             buf[j] = buf[j-1];
  321.         }
  322.         if (numDigits2 < numDigits) {
  323.             numDigits2++;
  324.         }
  325.         (*pointPtr)++;
  326.         buf[0] = '1';
  327.         break;
  328.         }
  329.  
  330.         buf[i] += 1;
  331.         if (buf[i] <= '9') {
  332.         break;
  333.         }
  334.         buf[i] = '0';
  335.     }
  336.     }
  337.  
  338.     if (numDigits2 <= 0) {
  339.     numDigits2 = 0;
  340.     *pointPtr = -afterPoint;
  341.     }
  342.     buf[numDigits2] = 0;
  343.     return numDigits2;
  344. }
  345.  
  346. /*
  347.  *----------------------------------------------------------------------
  348.  *
  349.  * vfprintf --
  350.  *
  351.  *    This utility routine does all of the real work of printing
  352.  *    formatted information.  It is called by printf, fprintf,
  353.  *    sprintf, vprintf, and vsprintf.
  354.  *
  355.  * Results:
  356.  *    The return value is the total number of characters printed.
  357.  *
  358.  * Side effects:
  359.  *    Information is output on stream.  See the manual page entry
  360.  *    for printf for details.
  361.  *
  362.  *----------------------------------------------------------------------
  363.  */
  364.  
  365. int
  366. vfprintf(stream, format, args)
  367.     register FILE *stream;    /* Where to output formatted results. */
  368.     register char *format;    /* Contains literal text and format control
  369.                  * sequences indicating how args are to be
  370.                  * printed.  See the man page for details. */
  371.     va_list args;        /* Variable number of values to be formatted
  372.                  * and printed. */
  373. {
  374.     int leftAdjust;        /* TRUE means field should be left-adjusted. */
  375.     int minWidth;        /* Minimum width of field. */
  376.     int precision;        /* Precision for field (e.g. digits after
  377.                  * decimal, or string length). */
  378.     int altForm;        /* TRUE means value should be converted to
  379.                  * an alternate form (depends on type of
  380.                  * conversion). */
  381.     register char c;        /* Current character from format string.
  382.                  * Eventually it ends up holding the format
  383.                  * type (e.g. 'd' for decimal). */
  384.     char pad;            /* Pad character. */
  385.     char buf[CVT_DBL_BUF_SIZE+10];
  386.                 /* Buffer used to hold converted numbers
  387.                  * before outputting to stream.  Must be
  388.                  * large enough for floating-point number
  389.                  * plus sign plus "E+XXX + null" */
  390.     char expBuf[CVT_INT_BUF_SIZE];
  391.                 /* Buffer to use for converting exponents. */
  392.     char *signChar;        /* This is the "+" or " " for the sign pos.  */
  393.     char *prefix;        /* Holds non-numeric stuff that precedes
  394.                  * number, such as "-" or "0x".  This is
  395.                  * kept separate to be sure we add padding
  396.                  * zeroes AFTER the prefix. */
  397.     register char *field;    /* Pointer to converted field. */
  398.     int actualLength;        /* Actual length of converted field. */
  399.     int point;            /* Location of decimal point, for "f" and
  400.                  * "e" conversions. */
  401.     int zeroPad;        /* Zeros to pad number with. */
  402.     int sign;            /* Also used for "f" and "e" conversions. */
  403.     int i, tmp;
  404.     int charsPrinted = 0;    /* Total number of characters output. */
  405.     char *end;
  406.     int fpError = FALSE;
  407.  
  408.     /*
  409.      * The main loop is to scan through the characters in format.
  410.      * Anything but a '%' is output directly to stream.  A '%'
  411.      * signals the start of a format field;  the formatting information
  412.      * is parsed, the next value from args is formatted and printed,
  413.      * and the loop goes on.
  414.      */
  415.  
  416.     for (c = *format; c != 0; format++, c = *format) {
  417.  
  418.     if (c != '%') {
  419.         putc(c, stream);
  420.         charsPrinted += 1;
  421.         continue;
  422.     }
  423.  
  424.     /*
  425.      * Parse off the format control fields.
  426.      */
  427.  
  428.     leftAdjust    = FALSE;
  429.     pad        = ' ';
  430.     minWidth    = 0;
  431.     precision    = -1;
  432.     altForm        = FALSE;
  433.     signChar    = "";
  434.     prefix        = "";
  435.     actualLength    = 0;
  436.     zeroPad        = 0;
  437.  
  438.     format++;  
  439.     c = *format;
  440.     while (TRUE) {
  441.         if (c == '-') {
  442.         leftAdjust = TRUE;
  443.         } else if (c == '0') {
  444.         pad = '0';
  445.         } else if (c == '#') {
  446.         altForm = TRUE;
  447.         } else if (c == '+') {
  448.         signChar = "+";
  449.         } else if (c== ' ') {
  450.         if (!*signChar) {
  451.             signChar = " ";
  452.         }
  453.         } else {
  454.         break;
  455.         }
  456.         format++;
  457.         c = *format;
  458.     }
  459.     if (isdigit(c)) {
  460.         minWidth = strtoul(format, &end, 10);
  461.         format = end;
  462.         c = *format;
  463.     } else if (c == '*') {
  464.         minWidth = va_arg(args, int);
  465.         format++; 
  466.         c = *format;
  467.     }
  468.     if (c == '.') {
  469.         format++; 
  470.         c = *format;
  471.         precision = 0;
  472.     }
  473.     if (isdigit(c)) {
  474.         precision = strtoul(format, &end, 10);
  475.         format = end;
  476.         c = *format;
  477.     } else if (c == '*') {
  478.         precision = va_arg(args, int);
  479.         format++; 
  480.         c = *format;
  481.     }
  482.     if (c == 'l') {            /* Ignored for compatibility. */
  483.         format++; 
  484.         c = *format;
  485.     }
  486.     if (c == 'h') {            /* Ignored for compatibility. */
  487.         format++; 
  488.         c = *format;
  489.     }
  490.  
  491.     /*
  492.      * Take action based on the format type (which is now in c).
  493.      */
  494.  
  495.     field = buf;
  496.     switch (c) {
  497.  
  498.         case 'D':
  499.         case 'd':
  500.         case 'i':
  501.         i = va_arg(args, int);
  502.         if (i < 0) {
  503.             prefix = "-";
  504.             i = -i;
  505.             actualLength = 1;
  506.         } else {
  507.             prefix = signChar;
  508.             actualLength = *prefix ? 1 : 0;
  509.         }
  510.         field = CvtUtoA((unsigned) i, 10, buf, &tmp, 0);
  511.         if (tmp < precision) {
  512.             zeroPad = precision-tmp;
  513.         }
  514.         actualLength += tmp+zeroPad;
  515.         break;
  516.         
  517.         case 'O':
  518.         case 'o':
  519.         i = va_arg(args, int);
  520.         field = CvtUtoA((unsigned) i, 8, buf, &tmp, 0);
  521.         if (tmp < precision) {
  522.             zeroPad = precision-tmp;
  523.         }
  524.         if (altForm && (i != 0) && zeroPad==0) {
  525.             prefix = "0";
  526.             actualLength = 1;
  527.         }
  528.         actualLength += tmp+zeroPad;
  529.         break;
  530.         
  531.         case 'X':
  532.         case 'x':
  533.         case 'p':
  534.         i = va_arg(args, int);
  535.         field = CvtUtoA((unsigned) i, 16, buf, &actualLength, c=='X');
  536.         if (actualLength < precision) {
  537.             zeroPad = precision-actualLength;
  538.             actualLength += zeroPad;
  539.         }
  540.         if (altForm) {
  541.             char *p;
  542.             if (c == 'X') {
  543.             if (i != 0) {
  544.                 prefix = "0X";
  545.                 actualLength += 2;
  546.             }
  547.             for (p = field; *p != 0; p++) {
  548.                 if (*p >= 'a') {
  549.                 *p += 'A' - 'a';
  550.                 }
  551.             }
  552.             } else if (i != 0) {
  553.             prefix = "0x";
  554.             actualLength += 2;
  555.             }
  556.         }
  557.         break;
  558.         
  559.         case 'U':
  560.         case 'u':
  561.         field = CvtUtoA(va_arg(args, unsigned), 10, buf,
  562.             &actualLength, 0);
  563.         if (actualLength < precision) {
  564.             zeroPad = precision-actualLength;
  565.             actualLength += zeroPad;
  566.         }
  567.         break;
  568.         
  569.         case 's':
  570.         field = va_arg(args, char *);
  571.         if (field == (char *) NULL) {
  572.             field = "(NULL)";
  573.         } 
  574.         actualLength = strlen(field);
  575.         if ((precision >= 0) && (precision < actualLength)) {
  576.             actualLength = precision;
  577.         }
  578.         pad = ' ';
  579.         break;
  580.  
  581.         case 'c':
  582.         buf[0] = va_arg(args, int);
  583.         actualLength = 1;
  584.         pad = ' ';
  585.         break;
  586.  
  587.         case 'F':
  588.         case 'f':
  589.         if (precision < 0) {
  590.             precision = 6;
  591.         } else if (precision > CVT_DBL_BUF_SIZE) {
  592.             precision = CVT_DBL_BUF_SIZE;
  593.         }
  594.  
  595.         /*
  596.          * Just generate the digits and compute the total length
  597.          * here.  The rest of the work will be done when the
  598.          * characters are actually output, below.
  599.          */
  600. #ifdef sun4
  601.          /*
  602.           * Varargs is not correctly implemented in gcc version 1.34
  603.           * for the sun4.  This problem should be fixed in the next
  604.           * version of the compiler, and this code can then be
  605.           * deleted.
  606.           */
  607.          {
  608.              union {
  609.                  long i[2];
  610.                  double d;
  611.              } u;
  612.  
  613.              u.i[0] = va_arg(args, long);
  614.              u.i[1] = va_arg(args, long);
  615.  
  616.              actualLength = CvtFtoA(u.d, CVT_DBL_BUF_SIZE,
  617.              precision, &point, &sign, field, &fpError);
  618.          }
  619. #else
  620.         actualLength = CvtFtoA(va_arg(args, double), CVT_DBL_BUF_SIZE,
  621.             precision, &point, &sign, field, &fpError);
  622. #endif
  623.         if (sign) {
  624.             prefix = "-";
  625.             actualLength += 1;
  626.         } else {
  627.             prefix = signChar;
  628.             actualLength += *prefix ? 1 : 0;
  629.         }
  630.         if (fpError) {
  631.             pad = ' ';
  632.             break;
  633.         }
  634.         if (point <= 0) {
  635.             actualLength += 1 - point;
  636.         }
  637.         if ((precision != 0) || (altForm)) {
  638.             actualLength += 1;
  639.         }
  640.         c = 'f';
  641.         break;
  642.  
  643.         case 'E':
  644.         case 'e':
  645.         if (precision < 0) {
  646.             precision = 6;
  647.         } else if (precision > CVT_DBL_BUF_SIZE-1) {
  648.             precision = CVT_DBL_BUF_SIZE-1;
  649.         }
  650. #ifdef sun4
  651.          /*
  652.           * Varargs is not correctly implemented in gcc version 1.34
  653.           * for the sun4.  This problem should be fixed in the next
  654.           * version of the compiler, and this code can then be
  655.           * deleted.
  656.           */
  657.          {
  658.              union {
  659.                  long i[2];
  660.                  double d;
  661.              } u;
  662.  
  663.              u.i[0] = va_arg(args, long);
  664.              u.i[1] = va_arg(args, long);
  665.  
  666.              actualLength = CvtFtoA(u.d, precision+1, -1,
  667.              &point, &sign, &buf[1], &fpError);
  668.          }
  669. #else
  670.         actualLength = CvtFtoA(va_arg(args, double), precision+1, -1,
  671.             &point, &sign, &buf[1], &fpError);
  672. #endif
  673.         if (fpError) {
  674.             pad = ' ';
  675.             field = &buf[1];
  676.             if (sign) {
  677.             prefix = "-";
  678.             actualLength += 1;
  679.             } else {
  680.             prefix = signChar;
  681.             actualLength += *prefix ? 1 : 0;
  682.             }
  683.             break;
  684.         }
  685.         eFromG:
  686.  
  687.         /*
  688.          * Insert a decimal point after the first digit of the number.
  689.          * If no digits after decimal point, then don't print decimal
  690.          * unless in altForm.
  691.          */
  692.  
  693.         buf[0] = buf[1];
  694.         buf[1] = '.';
  695.         if ((precision != 0) || (altForm)) {
  696.             field = buf + precision + 2;
  697.         } else {
  698.             field = &buf[1];
  699.         }
  700.  
  701.         /*
  702.          * Convert the exponent.
  703.          */
  704.         
  705.         *field = c;
  706.             field++;
  707.         point--;    /* One digit before decimal point. */
  708.         if (point < 0) {
  709.             *field = '-';
  710.             point = -point;
  711.         } else {
  712.             *field = '+';
  713.         }
  714.         field++;
  715.         if (point < 10) {
  716.             *field = '0';
  717.             field++;
  718.         }
  719.         strcpy(field, CvtUtoA((unsigned) point, 10, expBuf, &i, 0));
  720.         actualLength = (field - buf) + i;
  721.         field = buf;
  722.         if (sign) {
  723.             prefix = "-";
  724.             actualLength += 1;
  725.         } else {
  726.             prefix = signChar;
  727.             actualLength += *prefix ? 1 : 0;
  728.         }
  729.         break;
  730.  
  731.         case 'G':
  732.         case 'g': {
  733.         int eLength, fLength;
  734.  
  735.         if (precision < 0) {
  736.             precision = 6;
  737.         } else if (precision > CVT_DBL_BUF_SIZE-1) {
  738.             precision = CVT_DBL_BUF_SIZE-1;
  739.         } else if (precision == 0) {
  740.             precision = 1;
  741.         }
  742.  
  743. #ifdef sun4
  744.          /*
  745.           * Varargs is not correctly implemented in gcc version 1.34
  746.           * for the sun4.  This problem should be fixed in the next
  747.           * version of the compiler, and this code can then be
  748.           * deleted.
  749.           */
  750.          {
  751.              union {
  752.                  long i[2];
  753.                  double d;
  754.              } u;
  755.  
  756.              u.i[0] = va_arg(args, long);
  757.              u.i[1] = va_arg(args, long);
  758.  
  759.              actualLength = CvtFtoA(u.d, precision,
  760.              -1, &point, &sign, &buf[1], &fpError);
  761.          }
  762. #else
  763.         actualLength = CvtFtoA(va_arg(args, double), precision,
  764.             -1, &point, &sign, &buf[1], &fpError);
  765.  
  766. #endif
  767.         if (fpError) {
  768.             pad = ' ';
  769.             field = &buf[1];
  770.             if (sign) {
  771.             prefix = "-";
  772.             actualLength += 1;
  773.             } else {
  774.             prefix = signChar;
  775.             actualLength += *prefix ? 1 : 0;
  776.             }
  777.             break;
  778.         }
  779.         if (!altForm) {
  780.             for ( ; actualLength > 1; actualLength--) {
  781.             if (buf[actualLength] != '0') {
  782.                 break;
  783.             }
  784.             }
  785.         }
  786.         if ((actualLength > 1) || altForm) {
  787.             eLength = actualLength + 5;
  788.         } else {
  789.             eLength = actualLength + 4;
  790.         }
  791.         if (point <= 0) {
  792.             fLength = actualLength + 2 - point;
  793.         } else {
  794.             fLength = actualLength;
  795.             if (point < actualLength) {
  796.             fLength += 1;
  797.             } else if (altForm) {
  798.             fLength = point + 1;
  799.             } else {
  800.             fLength = point;
  801.             }
  802.         }
  803.  
  804.         /*
  805.          * Use "e" format if it results in fewer digits than "f"
  806.          * format, or if it would result in non-significant zeroes
  807.          * being printed.  Remember that precision means something
  808.          * different in "e" and "f" (digits after decimal) than it
  809.          * does in "g" (significant digits).
  810.          */
  811.  
  812.         if ((eLength < fLength) || (point > precision)) {
  813.             c += 'E' - 'G';
  814.             precision = actualLength-1;
  815.             goto eFromG;
  816.         }
  817.         c = 'f';
  818.         field = &buf[1];
  819.         actualLength = fLength;
  820.         if (sign) {
  821.             prefix = "-";
  822.             actualLength += 1;
  823.         } else {
  824.             prefix = signChar;
  825.             actualLength += *prefix ? 1 : 0;
  826.         }
  827.         break;
  828.         }
  829.  
  830.         case '%':
  831.         putc('%', stream);
  832.         charsPrinted += 1;
  833.         goto endOfField;
  834.  
  835.         case 0:
  836.         return charsPrinted;
  837.  
  838.         default:
  839.         putc(c, stream);
  840.         charsPrinted += 1;
  841.         goto endOfField;
  842.     }
  843.  
  844.     /*
  845.      * Things get tricky if we want to pad with 0's and left justify.
  846.      */
  847.     if (leftAdjust && pad == '0') {
  848.         if (c=='f' || c=='F' || c=='e' || c=='E' || c=='g' || c=='G') {
  849.         pad = ' ';
  850.         } else {
  851.         leftAdjust = FALSE;
  852.         }
  853.     }
  854.  
  855.     /* Handle pad characters on the left.  If the pad is '0', then
  856.      * padding goes after the prefix.  Otherwise, padding goes before
  857.      * the prefix.
  858.      */
  859.  
  860.     if (!leftAdjust) {
  861.         if (pad == '0') {
  862.         for ( ; *prefix != 0; prefix++) {
  863.             putc(*prefix, stream);
  864.             charsPrinted += 1;
  865.             actualLength--;
  866.             minWidth--;
  867.         }
  868.         }
  869.         while (minWidth > actualLength) {
  870.         putc(pad, stream);
  871.         charsPrinted += 1;
  872.         minWidth --;
  873.         }
  874.     }
  875.  
  876.     /*
  877.      * Output anything left in the prefix.
  878.      */
  879.  
  880.     minWidth -= actualLength;
  881.     for ( ; *prefix != 0; prefix++) {
  882.         putc(*prefix, stream);
  883.         charsPrinted += 1;
  884.         actualLength--;
  885.     }
  886.  
  887.     /*
  888.      * Pad the digits to the right length with 0's.
  889.      */
  890.     for (; zeroPad>0; zeroPad--) {
  891.         putc('0', stream);
  892.         charsPrinted += 1;
  893.         actualLength--;
  894.     }
  895.  
  896.     /*
  897.      * "F" and "f" formats are handled specially here:  output
  898.      * everything up to and including the decimal point.
  899.      */
  900.  
  901.     if (c == 'f' && !fpError) {
  902.         if (point <= 0) {
  903.         if (actualLength > 0) {
  904.             putc('0', stream);
  905.             charsPrinted += 1;
  906.             point++;
  907.             actualLength--;
  908.         }
  909.         if (actualLength > 0) {
  910.             charsPrinted += 1;
  911.             putc('.', stream);
  912.             actualLength--;
  913.         }
  914.         while ((point <= 0) && (actualLength > 0)) {
  915.             putc('0', stream);
  916.             charsPrinted += 1;
  917.             point++;
  918.             actualLength--;
  919.         }
  920.         } else {
  921.         while ((point > 0) && (actualLength > 0)) {
  922.             putc(*field, stream);
  923.             charsPrinted += 1;
  924.             field++;
  925.             point--;
  926.             actualLength--;
  927.         }
  928.         if (actualLength > 0) {
  929.             putc('.', stream);
  930.             charsPrinted += 1;
  931.             actualLength--;
  932.         }
  933.         }
  934.     }
  935.  
  936.     /*
  937.      * Output the contents of the field (for "f" format, this is
  938.      * just the stuff after the decimal point).
  939.      */
  940.  
  941.     charsPrinted += actualLength;
  942.     for ( ; actualLength > 0; actualLength--, field++) {
  943.         putc(*field, stream);
  944.         }
  945.  
  946.     /*
  947.      * Pad the right of the field, if necessary.
  948.      */
  949.  
  950.     while (minWidth > 0) {
  951.         putc(' ', stream);
  952.         charsPrinted += 1;
  953.         minWidth --;
  954.     }
  955.  
  956.     endOfField: continue;
  957.     }
  958.     return charsPrinted;
  959. }
  960.